package com.danco.training.bookshop.service.storage;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.danco.training.bookshop.comparator.OrderComparatorByOrderDate;
import com.danco.training.bookshop.comparator.OrderComparatorByPrice;
import com.danco.training.bookshop.comparator.OrderComparatorByState;
import com.danco.training.bookshop.entity.Book;
import com.danco.training.bookshop.entity.Claim;
import com.danco.training.bookshop.entity.Order;
import com.danco.training.bookshop.entity.storage.BookStorage;
import com.danco.training.bookshop.entity.storage.OrderStorage;



public class OrderStorageService implements Serializable{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = -1305548171488123635L;
	private OrderStorage orderStorage = OrderStorage.getOrderStorageInstance();
	private BookStorage bookStorage = BookStorage.getBookStorageInstance();
	private static final Logger logger = Logger.getLogger(OrderStorageService.class);
	
	private static OrderStorageService orderStorageServiceInstance;
	
	private transient OrderComparatorByOrderDate orderComparatorByOrderDate = new OrderComparatorByOrderDate();
	private transient  OrderComparatorByPrice orderComparatorByPrice = new OrderComparatorByPrice();
	private transient  OrderComparatorByState orderComparatorByState = new OrderComparatorByState();
	
	private OrderStorageService() {

	}
	
	public List<Order> getOrderList(){
		List<Order> res = new ArrayList<Order>();
		res = orderStorage.getOrders();
		logger.trace("Order list");
			return res;
	}
	
	public List<Integer> getOrderListId(){
		List<Integer> res = new ArrayList<Integer>();
		for (Order or :orderStorage.getOrders()) {
			res.add(or.getId())	;			
				}
			
		
		return res;
	
	}
	
	public int generateUnexistedId(){
		int i = 1;
		while(getOrderListId().contains(i)){
			i++;
		}
		return i;
	}
	public List<Order> getExecutedOrders(List<Order> orders){
		List<Order> res = new ArrayList<Order>();
		for (Order order : orders) {
			if (order.isExecuted()) {
					res.add(order);
					
				}
			
		}
		logger.trace("Excecuted orders  are founded");
			return res;
	}
	
	public List<Order> getNotExecutedOrders(List<Order> orders){
		List<Order> res = new ArrayList<Order>();
		for (Order order : orders) {
			if (!order.isExecuted()) {
					res.add(order);
					
				}
			
		}
		logger.trace("Not excecuted orders  are founded");
			return res;
	}
	
	public List<Order> getExecutedOrdersForPeriod(List<Order> orders, Date from, Date to ){
		List<Order> res = new ArrayList<Order>();
		for (Order order : getExecutedOrders(orders)) {
			
				if (order.getOrderDate().after(from)
						&& order.getOrderDate().before(to)) {
					res.add(order);		
				
			}
		}
		logger.trace("Excecuted orders for period are founded");
			return res;
	}

	public List<Order> sortOrdersByOrderDate(List<Order> orders) {
		orders.sort(orderComparatorByOrderDate);
		logger.trace("Orders are sorted by execution date");
		return orders;
	}

	public List<Order> sortOrdersByTotalPrice(List<Order> orders) {
		orders.sort(orderComparatorByPrice);
		logger.trace("Orders are sorted by total price");
		return orders;
	}

	public List<Order> sortOrdersByOrderState(List<Order> orders) {
		orders.sort(orderComparatorByState);
		logger.trace("Orders are sorted by state");
		return orders;

	}

	public List<Order> sortExecutedOrdersByOrderDate(List<Order> orders,
			Date from, Date to) {
		List<Order> res = new ArrayList<Order>();
		res = getExecutedOrdersForPeriod(orders, from, to);
		res.sort(orderComparatorByOrderDate);
		logger.trace("Executed orders are sorted by execution date");
		
		return res;
	}

	public List<Order> sortExecutedOrdersByPrice(List<Order> orders, Date from,
			Date to) {
		List<Order> res = new ArrayList<Order>();
		res = getExecutedOrdersForPeriod(orders, from, to);
		res.sort(orderComparatorByPrice);
		logger.trace("Executed orders are sorted by price");
		return res;
	}
	
	
	
	
	public Order getOrderById( int id){
		for (Order order: orderStorage.getOrders()){
			if ( order.getId()==id){
				logger.trace("Order is founded in Orderstorage by id");
				return order;
			}
			
		}
		logger.info("Order not founded in Orderstorage ");
		return null;
	}

	public boolean addBookToOrder(Order order, Book book) {

		try{
		if (order.getBooks().contains(book)) {
			for (Book b : order.getBooks()) {
				if (b.getId() == book.getId()) {
					b.setQuantity((b.getQuantity()) + 1);
					logger.trace("Instance of the existing book is added in Order");
				}
				
			}
		}
			else{
				book.setQuantity(1);
				order.getBooks().add(book);
				logger.trace("Instance of the new book is added in Order");
			}
		
		order.setTotalPrice(countPrice(order));
		addOrder(order);
		return true;
		}
		catch(Exception e){
			logger.error(e.getMessage(),e);
			return false;
		}
	}

	public boolean removeBookFromOrder(Order order, Book book) {
		try{
		if (order.getBooks().contains(book)){
		if (order.getBooks().remove(book)) {
			order.setTotalPrice(countPrice(order));
			logger.trace("Instance of book is removed from Order");
			
		}
		}
		return true;
		}
		catch (Exception e){
			logger.error(e.getMessage(),e);
		   return false;
		}
		

	}

	

	public double countPrice(Order order) {
		double sum = 0;
		for (Book book : order.getBooks()) {
			sum += book.getPrice()*book.getQuantity();
		}
		return sum;
	}
	
	public Order createOrderCopy(Order order) throws CloneNotSupportedException{
		Order copy;
		
		copy = order.clone();
		copy.setBooks(order.getBooks());
		copy.setExecuted(order.isExecuted());
		copy.setTotalPrice(order.getTotalPrice());
		copy.setOrderDate(order.getOrderDate());
		copy.setId(generateUnexistedId());
		addOrder(copy);
		return copy;
	}

	public boolean addOrder(Order order) {
		
			return orderStorage.getOrders().add(order) ;
			

	}

	public boolean executeOrderById(int id) {

				getOrderById(id).setExecuted(true);
				getOrderById(id).setOrderDate(new Date());

				for (Book b : bookStorage.getBooks()) {
					if (getOrderById(id).getBooks().contains(b)) {
						b.setQuantity(b.getQuantity() - 1);
					}
					else {
						b.setAvailable(false);
					}
				}
				return true;
			
	}

	public boolean rejectOrder(int index) {

		System.out.println("Order is rejected");
		
		return true;
	}


	public static OrderStorageService getOrderStorageServiceInstance() {
		if(orderStorageServiceInstance == null){
			orderStorageServiceInstance = new OrderStorageService();
		}
		return orderStorageServiceInstance;
	}


	

}
